package json5

import (
	"bufio"
	"bytes"
	"testing"
)

func Test_PrintJson(t *testing.T) {
	var val interface{}
	var exp, act string

	test := func(i interface{}) string {
		w := new(bytes.Buffer)
		bufw := bufio.NewWriter(w)
		if e := PrintJson(i, bufw); e != nil {
			panic(e)
		}
		bufw.Flush()
		return w.String()
	}

	val = nil
	exp = "null\n"
	act = test(val)
	equal(t, exp, act, val)

	val = "value"
	exp = "value\n"
	act = test(val)
	equal(t, exp, act, val)

	val = -.123456E+78
	exp = "-1.23456e+77\n"
	act = test(val)
	equal(t, exp, act, val)

	// https://ru.wikipedia.org/wiki/JSON
	val = []Member{
		Member{"firstName", "Иван"},
		Member{"lastName", "Иванов"},
		Member{"address",
			[]Member{
				Member{"streetAddress", "Московское ш., 101, кв.101"},
				Member{"city", "Ленинград"},
				Member{"postalCode", 101101},
			},
		},
		Member{"phoneNumbers",
			[]interface{}{
				"812 123-1234",
				"916 123-4567",
			},
		},
	}
	exp = `{
  firstName: Иван,
  lastName: Иванов,
  address: {
    streetAddress: "Московское ш., 101, кв.101",
    city: Ленинград,
    postalCode: 101101
  },
  phoneNumbers: [
    812 123-1234,
    916 123-4567
  ]
}
`
	act = test(val)
	equal(t, exp, act, val)

	// https://en.wikipedia.org/wiki/JSON
	val = []Member{
		Member{"firstName", "John"},
		Member{"lastName", "Smith"},
		Member{"isAlive", true},
		Member{"age", 27},
		Member{"address",
			[]Member{
				Member{"streetAddress", "21 2nd Street"},
				Member{"city", "New York"},
				Member{"state", "NY"},
				Member{"postalCode", "10021-3100"},
			},
		},
		Member{"phoneNumbers",
			[]interface{}{
				[]Member{
					Member{"type", "home"},
					Member{"number", "212 555-1234"},
				},
				[]Member{
					Member{"type", "office"},
					Member{"number", "646 555-4567"},
				},
				[]Member{
					Member{"type", "mobile"},
					Member{"number", "123 456-7890"},
				},
			},
		},
		Member{"children", []interface{}{}},
		Member{"spouse", nil},
	}
	exp = `{
  firstName: John,
  lastName: Smith,
  isAlive: true,
  age: 27,
  address: {
    streetAddress: 21 2nd Street,
    city: New York,
    state: NY,
    postalCode: 10021-3100
  },
  phoneNumbers: [
    {
      type: home,
      number: 212 555-1234
    },
    {
      type: office,
      number: 646 555-4567
    },
    {
      type: mobile,
      number: 123 456-7890
    }
  ],
  children: [],
  spouse: null
}
`
	act = test(val)
	equal(t, exp, act, val)

}

func Test_printElement(t *testing.T) {
	var val interface{}
	var exp, act string

	test := func(i interface{}) string {
		w := new(bytes.Buffer)
		bufw := bufio.NewWriter(w)
		if e := printElement(i, bufw, 1); e != nil {
			panic(e)
		}
		bufw.Flush()
		return w.String()
	}

	val = nil
	exp = "null"
	act = test(val)
	equal(t, exp, act, val)

	val = true
	exp = "true"
	act = test(val)
	equal(t, exp, act, val)

	val = false
	exp = "false"
	act = test(val)
	equal(t, exp, act, val)

	val = -12345.876
	exp = "-12345.876"
	act = test(val)
	equal(t, exp, act, val)

	val = []Member{
		Member{"key", []interface{}{"item1", "item2"}},
	}
	exp = `{
    key: [
      item1,
      item2
    ]
  }`
	act = test(val)
	equal(t, exp, act, val)

	val = []interface{}{
		"item",
		[]Member{Member{"key", "value"}},
	}
	exp = `[
    item,
    {
      key: value
    }
  ]`
	act = test(val)
	equal(t, exp, act, val)

}

func Test_printObject(t *testing.T) {
	var val []Member
	var exp, act string

	test := func(o []Member) string {
		w := new(bytes.Buffer)
		bufw := bufio.NewWriter(w)
		if e := printObject(o, bufw, 1); e != nil {
			panic(e)
		}
		bufw.Flush()
		return w.String()
	}

	val = []Member{}
	exp = "{}"
	act = test(val)
	equal(t, exp, act, val)

	val = []Member{
		Member{"key", "value"},
	}
	exp = `{
  key: value
}`
	act = test(val)
	equal(t, exp, act, val)

	val = []Member{
		Member{"key1", "value1"},
		Member{"key2", "value2"},
	}
	exp = `{
  key1: value1,
  key2: value2
}`
	act = test(val)
	equal(t, exp, act, val)

}

func Test_printArray(t *testing.T) {
	var val []interface{}
	var exp, act string

	test := func(a []interface{}) string {
		w := new(bytes.Buffer)
		bufw := bufio.NewWriter(w)
		if e := printArray(a, bufw, 1); e != nil {
			panic(e)
		}
		bufw.Flush()
		return w.String()
	}

	val = []interface{}{}
	exp = "[]"
	act = test(val)
	equal(t, exp, act, val)

	val = []interface{}{"item"}
	exp = `[
  item
]`
	act = test(val)
	equal(t, exp, act, val)

	val = []interface{}{"one", "two", "three"}
	exp = `[
  one,
  two,
  three
]`
	act = test(val)
	equal(t, exp, act, val)

}

func Test_printString(t *testing.T) {
	var val, exp, act string

	test := func(s string) string {
		w := new(bytes.Buffer)
		bufw := bufio.NewWriter(w)
		if e := printString(s, bufw); e != nil {
			panic(e)
		}
		bufw.Flush()
		return w.String()
	}

	val = ""
	exp = ``
	act = test(val)
	equal(t, exp, act, val)

	val = "text"
	exp = `text`
	act = test(val)
	equal(t, exp, act, val)

	val = "text \n\r\t\b\f\\ / text"
	exp = `"text \n\r\t\b\f\\ / text"`
	act = test(val)
	equal(t, exp, act, val)

	val = "one \"TWO\" three"
	exp = `"one \"TWO\" three"`
	act = test(val)
	equal(t, exp, act, val)

	val = " { key : [ 'item1' , \"item2\" ] } "
	exp = `" { key : [ \'item1\' , \"item2\" ] } "`
	act = test(val)
	equal(t, exp, act, val)

	val = "\u221A12345"
	exp = `√12345`
	act = test(val)
	equal(t, exp, act, val)

}
